package ast

import (
	"github.com/shopspring/decimal"
	"qiuya/util"
	"regexp"
	"strings"
)

const (
	OP_IN         = 0x01
	OP_EQ         = 0x02
	OP_LT         = 0x03
	OP_GT         = 0x04
	OP_GTE        = 0x05
	OP_LTE        = 0x06
	OP_NEQ        = 0x07
	OP_REGEXP     = 0x08
	OP_ELEM_MATCH = 0x09
)

func Match(node interface{}, data interface{}) bool {
	switch node.(type) {
	case *AndOr:
		andor := node.(*AndOr)
		if andor.IsAnd {
			for _, v := range andor.Children {
				if !Match(v, data) {
					return false
				}
			}
			return true
		} else {
			var flag bool
			for _, v := range andor.Children {
				flag = flag || Match(v, data)
			}
			return flag
		}
	case *Op:
		op := node.(*Op)
		switch op.Operator {
		case OP_EQ:
			return util.Equal(data, op.Value) //data == op.Value
		case OP_NEQ:
			return !util.Equal(data, op.Value)
		case OP_LT:
			r, err := util.Compare(data, op.Value)
			return err == nil && r < 0
		case OP_GT:
			r, err := util.Compare(data, op.Value)
			return err == nil && r > 0
		case OP_LTE:
			r, err := util.Compare(data, op.Value)
			return err == nil && r <= 0
		case OP_GTE:
			r, err := util.Compare(data, op.Value)
			return err == nil && r >= 0
		case OP_IN:
			for _, v := range op.Value.([]interface{}) {
				if util.Equal(v, data) {
					return true
				}
			}
			return false

		case OP_REGEXP:
			if str, ok := data.(string); ok {
				return op.Value.(*regexp.Regexp).Match([]byte(str))
			}
			return false

		case OP_ELEM_MATCH:
			if arr, ok := data.([]interface{}); ok {
				for _, vv := range arr {
					if Match(op.Value, vv) {
						return true
					}
				}
			}
			return false
		}
	case *Scope:
		scope := node.(*Scope)
		if v, ok := data.(map[string]interface{}); ok {
			return Match(scope.Next, v[scope.Key])
		} else if v, ok := data.([]interface{}); ok {
			for _, vv := range v {
				switch vv.(type) {
				case map[string]interface{}:
					if Match(scope.Next, vv.(map[string]interface{})[scope.Key]) {
						return true
					}
					break
				default:
					if Match(scope.Next, vv) {
						return true
					}
					break
				}
			}
			return false
			//i, err := strconv.Atoi(scope.Key)
			//if err != nil {
			//	return false
			//}
			//return Match(scope.Next, v[i])
		} else {
			return false
		}

	}

	return false

	//	switch node.Operator {
	//	case "and":
	//		return Match(node.Left.(*QueryTreeNode), data) && Match(node.Right.(*QueryTreeNode), data)
	//	case "or":
	//		return Match(node.Left.(*QueryTreeNode), data) || Match(node.Right.(*QueryTreeNode), data)
	//	case "eq":
	//		return data== node.Right
	//	case "scope":
	//		return Match(node.Right.(*QueryTreeNode), (data.(map[string]interface{}))[node.Left.(string)])
	//	}
	//	return false
}

func ParseQuery(query map[string]interface{}) (interface{}, error) {
	return parseMap(query, true)
}

func parseMap(query map[string]interface{}, isAnd bool) (interface{}, error) {
	node := NewAndOr(isAnd)
	return node.addMap(query)
}

func parsePair(k string, v interface{}) (interface{}, error) {
	//and
	switch k {
	case "$and":
		//v 必定为数组
		if arr, ok := v.([]interface{}); ok {
			node := NewAnd()
			return node.addArray(arr)
		}
		break
	case "$or":
		//v 必定为数组
		if arr, ok := v.([]interface{}); ok && len(arr) > 0 {
			node := NewOr()
			return node.addArray(arr)
		}
		break
	case "$in":
		if arr, ok := v.([]interface{}); ok {
			return NewOp(OP_IN, arr), nil
		}
		break

	case "$eq":
		return NewOp(OP_EQ, v), nil
	case "$ne":
		return NewOp(OP_NEQ, v), nil
	case "$lt":
		return NewOp(OP_LT, v), nil
	case "$gt":
		return NewOp(OP_GT, v), nil
	case "$lte":
		return NewOp(OP_LTE, v), nil
	case "$gte":
		return NewOp(OP_GTE, v), nil
	case "$regex":
		reg, err := regexp.Compile(v.(string))
		if err != nil {
			return nil, err
		}
		return NewOp(OP_REGEXP, reg), nil
	case "$elemMatch":
		switch v.(type) {
		case map[string]interface{}:
			var next, err = parseMap(v.(map[string]interface{}), false)
			if err != nil {
				return nil, err
			}
			return NewOp(OP_ELEM_MATCH, next), nil

		default:
			var next, err = parseMap(map[string]interface{}{"$eq": v}, false)
			if err != nil {
				return nil, err
			}
			return NewOp(OP_ELEM_MATCH, next), nil
		}

	default:
		var i = -1
		if i = strings.IndexByte(k, '$'); i > -1 {
			return parsePair(k[:i], map[string]interface{}{k[i:]: v})
		}
		if i = strings.IndexByte(k, '.'); i > -1 {
			var child, err = parsePair(k[i+1:], v)
			if err != nil {
				return nil, err
			}
			return NewScope(k[:i], child), nil
		}
		switch v.(type) {
		case decimal.Decimal:
			return NewScope(k, NewOp(OP_EQ, v)), nil
		case string:
			return NewScope(k, NewOp(OP_EQ, v)), nil
		case map[string]interface{}:
			and, err := NewAnd().addMap(v.(map[string]interface{}))
			if err != nil {
				return nil, err
			}
			if and != nil {
				return NewScope(k, and), nil
			}
		}
		break
	}
	return nil, nil
}
